Skip to content

Rename the implicit result variable along with its function - #538

Open
kunalKumar-13 wants to merge 1 commit into
fortran-lang:masterfrom
kunalKumar-13:fix/rename-implicit-function-result
Open

Rename the implicit result variable along with its function#538
kunalKumar-13 wants to merge 1 commit into
fortran-lang:masterfrom
kunalKumar-13:fix/rename-implicit-function-result

Conversation

@kunalKumar-13

Copy link
Copy Markdown

Fixes #322

The bug

A Fortran function declared without a RESULT() clause returns through an
implicit result variable that shares the function's name:

real pure function sind(x)
    real, intent(in), value :: x
    sind = sin(x*((4.0*atan(1.0))/180.0))   ! <- implicit result variable
end function

Renaming sind renamed only the declaration and left the assignment alone,
producing code that no longer compiles.

Root cause

fortls models the implicit result variable as a distinct object with its own
FQSN. For the function above:

site resolves to FQSN
function sind(x) Function m::sind
sind = ... Variable m::sind::sind

get_all_references matches candidates with def_fqsn == var_def.FQSN
(langserver.py:994), so the body occurrence never matched and was dropped.

Two things worth noting, since the issue speculated about both:

  • This is not the intrinsic collision. A plain user function named
    myfunc fails identically, so sind shadowing the intrinsic is not
    involved. After this change the original sind case renames correctly and
    the sin/atan calls on the same line are still left alone.
  • Functions with an explicit RESULT() clause were never affected
    there both sites resolve to the same Variable, so they already matched.

textDocument/definition already resolved the body occurrence to the
function, so rename and definition disagreed with each other.

The fix

Link the function and its implicit result variable through the existing
override_cache, in both directions, so a rename started from the
declaration or from the body updates both sites. The link is only made when
result_name == name, i.e. when the result variable really is implicit;
explicit RESULT() clauses take the existing path untouched.

textDocument/references and documentHighlight share this code path and are
fixed by the same change:

before:  myfunc.f90 (3, 24)
after:   myfunc.f90 (3, 24)
         myfunc.f90 (5, 9)

Tests

Three tests plus a new fixture, test_rename_implicit_result.f90:

  • test_rename_implicit_function_result — rename from the declaration
  • test_rename_implicit_function_result_from_body — rename from the body
  • test_rename_explicit_function_result — explicit RESULT() unchanged

The first two fail on master and pass here; the third passes either way and
guards against a regression.

They assert the number of changes explicitly, because
check_rename_response zips changes against expectations and would otherwise
silently pass when a change is missing — which is exactly the failure mode
here.

Full suite: 184 passed. pre-commit clean.

A function declared without a RESULT() clause returns through an implicit
result variable that shares the function's name. fortls models it as a
distinct object with its own FQSN -- `mod::fun` for the function and
`mod::fun::fun` for the result variable -- so the equality test in
get_all_references never matched it and textDocument/rename left the
assignment in the body untouched, producing code that no longer compiles.

Link the two through the existing override_cache, in both directions, so a
rename started from either the declaration or the body updates both. This
only applies when the result variable is implicit; functions with an
explicit RESULT() clause are unaffected, and intrinsics are still skipped.

textDocument/references and documentHighlight share this code path and are
fixed by the same change.

Fixes fortran-lang#322
@kunalKumar-13
kunalKumar-13 requested a review from gnikit as a code owner August 27, 2026 09:20
Copilot AI lite review requested due to automatic review settings August 27, 2026 09:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes Fortran symbol rename behavior for functions declared without an explicit RESULT() clause, ensuring the implicit result variable in the function body is renamed together with the function (addressing #322). This aligns textDocument/rename behavior with textDocument/definition and also corrects textDocument/references / documentHighlight since they share the same reference-resolution path.

Changes:

  • Link a function and its implicit result variable bidirectionally during reference collection so both are treated as rename targets.
  • Add a new Fortran fixture covering implicit-result and explicit-RESULT() function cases.
  • Add three rename tests (rename from declaration, rename from body, and explicit RESULT() non-regression) and document the fix in the changelog.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
fortls/langserver.py Extends get_all_references to treat a function and its implicit result variable as linked rename/references targets via override_cache.
test/test_source/rename/test_rename_implicit_result.f90 Adds a fixture module demonstrating implicit result assignment vs explicit RESULT() behavior.
test/test_server_rename.py Adds regression tests for renaming implicit function results (from declaration and from body) and a guard for explicit RESULT() behavior.
CHANGELOG.md Records the fix under Unreleased.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@kunalKumar-13

Copy link
Copy Markdown
Author

The red X here is not this change. All 8 failing jobs fail at the same single step, Upload coverage to Codecov; Lint and Unittests pass in every one of them. It has been happening to every PR in the repo since about mid-July, including the project's own pre-commit-ci branch — I wrote it up with the evidence in #539.

I re-ran the CI sequence locally against this branch on Python 3.13 to be sure the change itself is clean:

black --check .                      ->  61 files unchanged
python -m fortls.schema; git diff    ->  no drift
pytest --doctest-modules -n auto     ->  196 passed

Nothing needed from me here as far as I can tell, but happy to rebase if that would help.

@kunalKumar-13

Copy link
Copy Markdown
Author

The red builds here are not from this change. On every failing job the only failing step is Upload coverage to CodecovSetup, Lint and Unittests all pass (197 passed), and the step fails on the action's own signature check:

gpg: Signature made Thu Jul  9 01:37:57 2026 UTC
gpg:                using RSA key 27034E7FDB850E0BBC2C62FF806BB28AED779869
gpg: Can't check signature: No public key
==> Could not verify signature. Please contact Codecov if problem continues
    Exiting...

It is repo-wide rather than specific to this PR: the most recent Tests run on master fails on the same step in the same job, and every push-triggered run since 2026-07-13 has failed the same way. #533 bumps codecov/codecov-action and may be the remedy, though its own checks predate the breakage so I can't say that from the runs alone.

Happy to rebase once CI is healthy if that would help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Function symbol rename does not rename the variable name inside the function

2 participants